/*
- 进程版服务器（端口8081）：主进程监听TCP，每接收一个连接就fork子进程处理
- 协议同上：接收double x， 返回double result
- 性能统计：记录fork耗时（每100次打印平均值avg_fork_us），子进程打印每次服务耗时service_us
- 资源管理：父进程关闭已交给子进程的client_sock，使用waitpid(..., WNOHANG)清理僵尸进程；子进程处理完成后_exit(0)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>

// 计算函数：F(x) = x^2 + 2x + 1
static double F(double x) {
    return x * x + 2 * x + 1;
}

static void handle_client_process(int client_sock) {
    // 子进程读取x，计算并返回结果
    double x;
    if (read(client_sock, &x, sizeof(double)) != sizeof(double)) {
        close(client_sock);
        _exit(1);
    }
    double result = F(x);
    write(client_sock, &result, sizeof(double));
    close(client_sock);
}

int main() {
    // 创建监听socket
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock < 0) {
        perror("socket");
        return 1;
    }
    int opt = 1;
    setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in server_addr = {0};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8081); // 与线程服务器使用不同端口
    server_addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind");
        return 1;
    }
    if (listen(server_sock, 64) < 0) {
        perror("listen");
        return 1;
    }
    printf("Process Server running on 8081...\n");

    struct timeval start, end;
    long long total_us_fork = 0;
    long long total_us_service = 0;
    unsigned long long requests = 0;

    while (1) {
        int client_sock = accept(server_sock, NULL, NULL);
        if (client_sock < 0) {
            perror("accept");
            continue;
        }

        // 记录fork前后时间，计算派生耗时
        gettimeofday(&start, NULL);
        pid_t pid = fork();
        gettimeofday(&end, NULL);
        long long fork_us = (end.tv_sec - start.tv_sec) * 1000000LL + (end.tv_usec - start.tv_usec);
        total_us_fork += fork_us;

        if (pid < 0) {
            perror("fork");
            close(client_sock);
            continue;
        } else if (pid == 0) {
            // child process handles client
            struct timeval s2, e2;
            gettimeofday(&s2, NULL);
            handle_client_process(client_sock);
            gettimeofday(&e2, NULL);
            long long service_us = (e2.tv_sec - s2.tv_sec) * 1000000LL + (e2.tv_usec - s2.tv_usec);
            // report per-request service time to stdout
            fprintf(stdout, "[child %d] service_us=%lld\n", getpid(), service_us);
            _exit(0);
        } else {
            // 父进程关闭client socket并统计请求计数
            close(client_sock);
            requests++;
            // 非阻塞清理已结束的子进程，避免僵尸
            while (waitpid(-1, NULL, WNOHANG) > 0) {}

            if (requests % 100 == 0) {
                double avg_fork_us = (requests ? (double)total_us_fork / (double)requests : 0.0);
                printf("[parent] requests=%llu avg_fork_us=%.2f\n", requests, avg_fork_us);
            }
        }
    }
}